package com.qs.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.date.format.FastDateFormat;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qs.constant.CategoryConstant;
import com.qs.constant.RedisConstant;
import com.qs.exception.ServiceException;
import com.qs.mapper.*;
import com.qs.pojo.dto.OrderDetailDto;
import com.qs.pojo.dto.OrderDto;
import com.qs.pojo.entity.*;
import com.qs.pojo.vo.GoodsStockLockVo;
import com.qs.pojo.vo.WeekDayVo;
import com.qs.pojo.vo.YearOrderVo;
import com.qs.response.Response;
import com.qs.response.ResponseEnum;
import com.qs.service.IAsyncService;
import com.qs.service.IOrderInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 订单信息表 服务实现类
 * </p>
 *
 * @author author
 * @since 2023-12-07
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements IOrderInfoService {

    static float clothes = 0.0f;
    static float shoes = 0.0f;
    static float decoration = 0.0f;
    static float electronic_equipment = 0.0f;
    static float furniture = 0.0f;
    static float food = 0.0f;
    static float medicine = 0.0f;

    private final OrderItemMapper orderItemMapper;

    private final RedisTemplate redisTemplate;

    private final GoodsMapper goodsMapper;

    private final CartMapper cartMapper;

    private final PayInfoMapper payInfoMapper;

    private final IAsyncService asyncService;

    private final CategoryMapper categoryMapper;

    private static final DefaultRedisScript<Boolean> REDIS_SCRIPT;

    /**
     * 初始化lua脚本
     */
    static {
        REDIS_SCRIPT = new DefaultRedisScript<Boolean>();
        REDIS_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));
        REDIS_SCRIPT.setResultType(Boolean.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response saveOrderInfo(OrderDto orderDto, String orderId, Integer userId) {
        if(StringUtils.isEmpty(orderId)){
            throw new ServiceException(ResponseEnum.ORDER_ID_EXCEPTION);
        }
        //先查询订单是否是已超时状态
        String redisOrderId = (String) redisTemplate.opsForValue().get(RedisConstant.ORDER_ID + orderId);
        if(StringUtils.isBlank(redisOrderId)){
            //说明订单已超时，将锁定的商品库存释放
            List<GoodsStockLockVo> stockLockVoList = (List<GoodsStockLockVo>) redisTemplate.opsForValue().get(RedisConstant.GOODS_STOCK_LOCK + orderId);
            if(!CollectionUtils.isEmpty(stockLockVoList)){
                List<Integer> goodsId = stockLockVoList.stream().map(GoodsStockLockVo::getGoodsId).collect(Collectors.toList());
                asyncService.deductionLockStock(goodsId,orderId);
                //异步将order_cart的记录删除
                asyncService.deleteOrderCart(orderId,userId);
                //根据orderId将超时订单记录qs_pay_info数据删除
                asyncService.deleteOrderIdExpire(orderId);
            }
            return Response.error(ResponseEnum.ORDER_ID_EXPIRE.getCode(),ResponseEnum.ORDER_ID_EXPIRE.getMessage());
        }
        //lua脚本保证原子性操作：TODO:解决幂等问题
        //拿着orderId到redis中查询
        //如果redis中有相同orderId,则说明是正常提交订单，把redis中的orderId删除，
        // 这个过程要保证原子性操作，由lua脚本保证。
        Boolean flag = (Boolean) redisTemplate.execute(REDIS_SCRIPT, Arrays.asList(RedisConstant.ORDER_ID + orderId), orderId);
        //如果redis中没有相同orderId,则说明是重复提交订单，不再往下进行
        if(!flag){
            throw new ServiceException(ResponseEnum.DO_NOT_REPLACE_SUBMIT);
        }
        //保存order_info表数据
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setOrderId(orderId);
        orderInfo.setAddressId(orderDto.getAddressId());
        orderInfo.setUserId(orderDto.getUserId());
        orderInfo.setTotalPrice(orderDto.getTotalPrice());
        baseMapper.insert(orderInfo);

        //保存order_item表数据
        Integer[] cartIds = orderDto.getCartId();
        for (int i = 0; i < cartIds.length; i++) {
            Cart cart = cartMapper.selectById(cartIds[i]);
            Goods goods = goodsMapper.selectById(cart.getGoodsId());
            //先查询是否有相同orderId和goodsId的数据
            QueryWrapper<OrderItem> orderItemWrapper = new QueryWrapper<>();
            orderItemWrapper.eq("order_id",orderId);
            orderItemWrapper.eq("goods_id",goods.getId());
            OrderItem selectOne = orderItemMapper.selectOne(orderItemWrapper);
            if(null == selectOne){
                //说明不存在，直接插入数据
                OrderItem orderItem = new OrderItem();
                orderItem.setOrderId(orderId);
                orderItem.setGoodsId(goods.getId());
                orderItem.setNumber(cart.getNumber());
                orderItem.setSubTotalPrice(cart.getNumber() * goods.getPrice());
                orderItemMapper.insert(orderItem);
            }else{
                //存在则说明是同一个用户在同一个订单下的同一件商品，只需将数量相加即可
                selectOne.setNumber(selectOne.getNumber() + cart.getNumber());
                orderItemMapper.updateById(selectOne);
            }
        }
        asyncService.saveUserGoodsLog(orderId,userId,cartIds);

        //异步释放库存
        asyncService.deductionStock(orderDto.getCartId(),orderId);

        //异步删除已生成订单中的购物车数据
        asyncService.deleteCartSelected(orderDto.getCartId());

        //异步将order_cart的记录删除
        asyncService.deleteOrderCart(orderId,userId);

        return Response.success();
    }

    @Override
    public List<YearOrderVo> getYearData(Integer userId) {
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        List<OrderInfo> orderInfos = baseMapper.selectList(wrapper);
        if(!CollectionUtils.isEmpty(orderInfos)){
            //订单数据过滤，过滤出今年订单数据
            List<YearOrderVo> yearOrderVos = currentYearOrder(orderInfos);
            return yearOrderVos;
        }
        return null;
    }

    @Override
    public float getYearTotalData(Integer userId) {
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        List<OrderInfo> orderInfos = baseMapper.selectList(wrapper);
        //将当年的数据过滤出来
        List<OrderInfo> currentYearOrderInfo = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        orderInfos.stream().forEach(item -> {
            String currentTime = LocalDateTimeUtil.format(LocalDateTimeUtil.parse(item.getCreateTime().toString()), DatePattern.NORM_YEAR_PATTERN);
            int year = DateUtil.year(new Date());
            if(String.valueOf(year).equalsIgnoreCase(currentTime)){
                currentYearOrderInfo.add(item);
            }
        });
        //查询并封装数据
        float totalYear = 0.0f;
        if(!CollectionUtils.isEmpty(currentYearOrderInfo)){
            List<YearOrderVo> finallData = new ArrayList<>();
            for (OrderInfo item : currentYearOrderInfo) {
                totalYear += item.getTotalPrice();
            }
            return totalYear;
        }
        return 0.0f;
    }

    @Override
    public List<Float> findWeekdayData(Integer userId) {
        List<WeekDayVo> weekdayData = baseMapper.findWeekdayData(userId);
        List<Float> list = new ArrayList<>(Arrays.asList(0.0f, 0.0f, 0.0f, 0.0f,0.0f, 0.0f, 0.0f));
        if(!CollectionUtils.isEmpty(list)){
            for (WeekDayVo vo : weekdayData) {
                switch (vo.getDay()) {
                    case 1:
                        //星期天
                        list.add(6,vo.getPrice());
                        break;
                    case 2:
                        //星期一
                        list.add(0,vo.getPrice());
                        break;
                    case 3:
                        //星期二
                        list.add(1,vo.getPrice());
                        break;
                    case 4:
                        //星期三
                        list.add(2,vo.getPrice());
                        break;
                    case 5:
                        //星期四
                        list.add(3,vo.getPrice());
                        break;
                    case 6:
                        //星期五
                        list.add(4,vo.getPrice());
                        break;
                    case 7:
                        //星期六
                        list.add(5,vo.getPrice());
                        break;
                    default:
                        break;
                }
            }
        }
        return list;
    }

    private List<YearOrderVo> currentYearOrder(List<OrderInfo> orderInfos) {
        //将当年的数据过滤出来
        List<OrderInfo> currentYearOrderInfo = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        orderInfos.stream().forEach(item -> {
            String currentTime = LocalDateTimeUtil.format(LocalDateTimeUtil.parse(item.getCreateTime().toString()), DatePattern.NORM_YEAR_PATTERN);
            int year = DateUtil.year(new Date());
            if(String.valueOf(year).equalsIgnoreCase(currentTime)){
                currentYearOrderInfo.add(item);
            }
        });
        //查询并封装数据
        List<YearOrderVo> finallData = new ArrayList<>();
        if(!CollectionUtils.isEmpty(currentYearOrderInfo)){
            for (OrderInfo item : currentYearOrderInfo) {
                QueryWrapper<OrderItem> wrapper = new QueryWrapper<>();
                wrapper.eq("order_id",item.getOrderId());
                List<OrderItem> orderItems = orderItemMapper.selectList(wrapper);
                finallData = getFinallData(orderItems);
            }
            return finallData;
        }
        return null;
    }

    private List<YearOrderVo> getFinallData(List<OrderItem> orderItems) {
        if(!CollectionUtils.isEmpty(orderItems)){
            for (OrderItem item : orderItems) {
                Goods goods = goodsMapper.selectById(item.getGoodsId());
                QueryWrapper<Category> wrapper = new QueryWrapper<>();
                wrapper.eq("name",goods.getCategory());
                Category category = categoryMapper.selectOne(wrapper);
                Category parentCategory = categoryMapper.selectById(category.getPid());
                switch (parentCategory.getName()) {
                    case CategoryConstant.CLOTHES:
                        clothes += item.getSubTotalPrice();
                        break;
                    case CategoryConstant.FOOD:
                        food += item.getSubTotalPrice();
                        break;
                    case CategoryConstant.SHOES:
                        shoes += item.getSubTotalPrice();
                        break;
                    case CategoryConstant.ELECTRONIC_EQUIPMENT:
                        electronic_equipment += item.getSubTotalPrice();
                        break;
                    case CategoryConstant.MEDICINE:
                        medicine += item.getSubTotalPrice();
                        break;
                    case CategoryConstant.FURNITURE:
                        furniture += item.getSubTotalPrice();
                        break;
                    case CategoryConstant.DECORATION:
                        decoration += item.getSubTotalPrice();
                        break;
                    default: break;
                }
            }
            return getYearOrderVoList();
        }
        return null;
    }

    private List<YearOrderVo> getYearOrderVoList() {
        List<YearOrderVo> list = new ArrayList<YearOrderVo>();
        YearOrderVo yearOrderVo1 = new YearOrderVo();
        yearOrderVo1.setValue(clothes);
        yearOrderVo1.setName("服装");
        YearOrderVo yearOrderVo2 = new YearOrderVo();
        yearOrderVo2.setValue(shoes);
        yearOrderVo2.setName("鞋品");
        YearOrderVo yearOrderVo3 = new YearOrderVo();
        yearOrderVo3.setValue(decoration);
        yearOrderVo3.setName("装饰");
        YearOrderVo yearOrderVo4 = new YearOrderVo();
        yearOrderVo4.setValue(electronic_equipment);
        yearOrderVo4.setName("电子设备");
        YearOrderVo yearOrderVo5 = new YearOrderVo();
        yearOrderVo5.setValue(furniture);
        yearOrderVo5.setName("家具");
        YearOrderVo yearOrderVo6 = new YearOrderVo();
        yearOrderVo6.setValue(food);
        yearOrderVo6.setName("食物");
        YearOrderVo yearOrderVo7 = new YearOrderVo();
        yearOrderVo7.setValue(medicine);
        yearOrderVo7.setName("药品");
        list.add(yearOrderVo1);
        list.add(yearOrderVo2);
        list.add(yearOrderVo3);
        list.add(yearOrderVo4);
        list.add(yearOrderVo5);
        list.add(yearOrderVo6);
        list.add(yearOrderVo7);
        return list;
    }
}
